package com.atguigu.gmall.order.service.impl;

import com.atguigu.gmall.cart.model.CartInfo;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.atguigu.gmall.product.model.SkuInfo;
import com.atguigu.gmall.service.CartService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * title:
 * author: Gyh
 * date:2023-05-05 16:56
 * Description:
 */
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    /**
     * 添加购物车到Redis中
     *  <RedisKey<hashKey,hashValue>>
     * @param userId 用户ID
     * @param skuId 商品SkuId
     * @param skuNum 商品加购数量
     * @return
     */
    @Override
    public void addToCart(String userId, Long skuId, Integer skuNum) {
        //创建购物车RedisKey
        String redisKey = getCartKey(userId);
        //判断当前商品Id是否存在hash接口中
            //创建某个用户购物车的操作对象(新Api),泛型<RedisKey<hashKey,hashValue>>
        BoundHashOperations<String,String,CartInfo> hashOps = redisTemplate.boundHashOps(redisKey);
        CartInfo cartInfo = null;
        if (hashOps.hasKey(skuId.toString())){
            //如果存在就可以对商品数量进行累加,并修改更新时间
            cartInfo = hashOps.get(skuId.toString());
            cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
            cartInfo.setUpdateTime(new Date());
        }else {
            //不存在就创建新CarInfo对象存入Redis中,第一次添加购物车
            //远程调用商品微服务获取商品信息
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
            if (skuInfo != null){
                cartInfo = new CartInfo();
                cartInfo.setSkuPrice(skuPrice);
                cartInfo.setCartPrice(skuPrice);
                cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
                cartInfo.setSkuId(skuId);
                cartInfo.setSkuName(skuInfo.getSkuName());
                cartInfo.setSkuNum(skuNum);
                cartInfo.setUserId(userId);
                cartInfo.setUpdateTime(new Date());
                cartInfo.setCreateTime(new Date());
            }
        }
        //无论是否新增或修改购物车,都保存到redis中
        hashOps.put(skuId.toString(),cartInfo);
    }

    /**
     * 查询购物车列表
     *  不合并购物车情况
     *  --用户未登录,直接返回未登录临时id购物车列表
     *  --用户从未登录变为登录状态,而未登录购物车没有数据时,直接返回已登录的购物车列表
     *  合并购物车情况
     *  --用户在未登录状态下添加商品到购物车中(未登录购物车中有商品数据),用户进行登录后,
     *    将未登录购物车商品与已登录用户购物车商品进行合并,合并后删除未登录购物车中商品数据
     * @param userId 用户id
     * @param userTempId 用户临时id
     * @return
     */
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        //如果有临时用户id,那么在尝试获取临时id的购物车列表
        List<CartInfo> noLonginList = null;
        if (StringUtils.isNotBlank(userTempId)){
            BoundHashOperations noLoginHashOps = redisTemplate.boundHashOps(this.getCartKey(userTempId));
            noLonginList = noLoginHashOps.values();
        }
        //如果用户id为空(用户未登录),直接返回未登录临时id购物车列表
        if (StringUtils.isBlank(userId)){
            noLonginList.stream().sorted((o1, o2) -> {
                return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(), Calendar.SECOND);
            }).collect(Collectors.toList());
            return noLonginList;
        }

        //如果有用户id并且临时id购物车中有商品数据,则需要合并
            //查询已登录购物车的商品数据
        BoundHashOperations<String,String,CartInfo> loginHahOps = redisTemplate.boundHashOps(this.getCartKey(userId));
        List<CartInfo> loginCartList = loginHahOps.values();
        //合并购物车
        if (!CollectionUtils.isEmpty(noLonginList)){
            //遍历未登录购物车数据,判断skuId是否在用户购物车hash结果中存在
            noLonginList.stream().forEach(noLoginCartInfo->{
                CartInfo loginCartInfo = loginHahOps.get(noLoginCartInfo.getSkuId().toString());
                //存在商品则数量添加
                if (loginCartInfo != null){
                    loginCartInfo.setSkuNum(loginCartInfo.getSkuNum()+noLoginCartInfo.getSkuNum());
                    loginCartInfo.setUpdateTime(new Date());
                    //得到未登录购物车上选中状态,合并后更新登录购物车选中状态
                    if (noLoginCartInfo.getIsChecked().intValue() == 1){
                        loginCartInfo.setIsChecked(1);
                    }
                    loginHahOps.put(loginCartInfo.getSkuId().toString(),loginCartInfo);
                }else {
                    //不存在商品则新增购物车商品
                    noLoginCartInfo.setUserId(userId);
                    loginHahOps.put(noLoginCartInfo.getSkuId().toString(),noLoginCartInfo);
                }
            });
        }
        //合并后删除未登录购物车中的所有商品数据
        redisTemplate.delete(this.getCartKey(userTempId));
        //再次查询redis中合并后购物车列表并排序
        loginCartList = loginHahOps.values();
        if (!CollectionUtils.isEmpty(loginCartList)){
            loginCartList.stream().sorted((o1, o2) -> {
                return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(),Calendar.SECOND);
            }).collect(Collectors.toList());
        }
        return loginCartList;
    }

    /**
     * 更新选中状态
     * @param userId
     * @param skuId
     * @param isChecked
     */
    @Override
    public void updateCheck(String userId, Long skuId, int isChecked) {
        BoundHashOperations<String,String,CartInfo> hashOps = redisTemplate.boundHashOps(this.getCartKey(userId));
        Boolean exists = hashOps.hasKey(skuId.toString());
        if (exists){
            CartInfo cartInfo = hashOps.get(skuId.toString());
            cartInfo.setIsChecked(isChecked);
            hashOps.put(skuId.toString(),cartInfo);
        }
    }

    /**
     * 删除购物车中商品
     * @param userId
     * @param skuId
     */
    @Override
    public void deleteCart(String userId, Long skuId) {
        BoundHashOperations<String,String,CartInfo> hashOps = redisTemplate.boundHashOps(this.getCartKey(userId));
        Boolean exists = hashOps.hasKey(skuId.toString());
        if (exists){
            hashOps.delete(skuId.toString());
        }
    }

    /**
     * 获取选中状态的购物车列表
     * @param userId
     * @return
     */
    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        //创建用户购物车的RedisKey
        String cartKey = getCartKey(userId.toString());
        //查询所有购物车商品列表
        BoundHashOperations<String,String,CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = hashOps.values();
        //将购物车信息中选中状态isChecked=1过滤出来
        if (!CollectionUtils.isEmpty(cartInfoList)){
            cartInfoList = cartInfoList.stream().filter(cartInfo -> {
                //过滤条件:true需要数据,false不需要数据
                return cartInfo.getIsChecked().intValue() == 1;
            }).collect(Collectors.toList());
        }
        return cartInfoList;
    }

    /**
     * 获取用户(登录用户/临时用户)购物车的RedisKey
     * 形式: user:用户ID:cart
     * @param userId
     * @return
     */
    private String getCartKey(String userId) {
        String redisKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        return redisKey;
    }
}
